package com.alpha.common.utils;

import com.alpha.module.app.model.ExcelData;
import com.alpha.module.app.model.UploadFileDTO;
import com.alpha.common.utils.storage.TencentCos;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * 文件工具类
 * @author zhaojiulin
 * @date 2020/2/27 13:34
 */
public class FileUtils {
    private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);

    private static  ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

    /**
     * 使用文件地址 上传到本地
     * @param fileVO 文件包装类
     */
    public static void channelTransferToFile(UploadFileDTO fileVO) {
        FileInputStream originFile = null;
        FileOutputStream targetFile = null;
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            // 源文件
            originFile = new FileInputStream(fileVO.getOriginPath());
            // 目标
            targetFile = new FileOutputStream(fileVO.getTargetPath() + fileVO.getFileName());
            // 源文件通道
            inChannel = originFile.getChannel();
            // 目标通道
            outChannel = targetFile.getChannel();
            // 从in通道写入out通道
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (originFile != null) {
                    originFile.close();
                }
                if (targetFile != null) {
                    targetFile.close();
                }
                if (inChannel != null) {
                    inChannel.close();
                }
                if (outChannel != null) {
                    outChannel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * base64 字符串上传到本地
     * @param fileVO 文件包装类
     * @return 文件类
     */
    public static File base64StringToFile(UploadFileDTO fileVO) {
        String fileType = fileVO.getBase64().split(";")[0].split("/")[1];
        String filePath = fileVO.getTargetPath() + fileVO.getFileName() + "." + fileType;
        try {
            String base = fileVO.getBase64().substring(fileVO.getBase64().indexOf(",") + 1);
            fileVO.setBase64(StrUtils.replaceBlank(base));
            Files.write(Paths.get(filePath), Base64.getDecoder().decode(fileVO.getBase64()), StandardOpenOption.CREATE);
        } catch (Exception e) {
            e.printStackTrace();

        }
        return new File(filePath);
    }

    /**
     * base64字符串转inputStream
     * @param fileVO 1
     * @return 1
     */
    public static InputStream base64StringToInputSteam(UploadFileDTO fileVO) {
        ByteArrayInputStream stream = null;
        try {
            String base = fileVO.getBase64().substring(fileVO.getBase64().indexOf(",") + 1);
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] bytes = decoder.decodeBuffer(StrUtils.replaceBlank(base));
            stream = new ByteArrayInputStream(bytes);
        } catch (Exception e) {
            e.printStackTrace();

        }
        return stream;
    }

    /**
     * 读取excel包装到list
     * @param filePath 文件相对路径
     * @return list
     * @throws Exception
     */
    public static List getCourseListByExcel(String filePath) throws Exception {
        List list = new ArrayList<>();
        Workbook work = getWorkbook(filePath);
        if (null == work) {
            throw new Exception("创建Excel工作薄为空！");
        }
        Sheet sheet = null;
        Row row = null;
        Cell cell = null;
        for (int i = 0; i < work.getNumberOfSheets(); i++) {
            sheet = work.getSheetAt(i);
            if (sheet == null) {
                continue;
            }
            for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
                row = sheet.getRow(j);
                if (row == null || row.getFirstCellNum() == j) {
                    continue;
                }
                List<Object> li = new ArrayList<>();
                for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {
                    cell = row.getCell(y);
                    System.out.println(cell);
                    // 日期类型转换
                    if (y == 3) {
                        //cell.setCellType(CellType.STRING);
                        double s1 = cell.getNumericCellValue();
                        Date date = HSSFDateUtil.getJavaDate(s1);
                        li.add(date);
                        continue;
                    }
                    li.add(cell);
                }
                list.add(li);
            }
        }
        return list;
    }

    /**
     * WorkBook
     * @param filePath 文件相对路径
     * @return
     * @throws Exception
     */
    private static Workbook getWorkbook(String filePath) throws Exception {
        Workbook book = null;
        String exStr = filePath.substring(filePath.lastIndexOf("."));
        InputStream in = new FileInputStream(filePath);
        if (".xls".equals(exStr)) {
            book = new HSSFWorkbook(in);
        } else if (".xlsx".equals(exStr)) {
            book = new XSSFWorkbook(in);
        } else {
            throw new Exception("请上传excel文件！");
        }
        return book;
    }

    /**
     * excel 转 对象 示例
     * @param excelPath 文件地址
     */
    public static void analysisExcel(String excelPath) {
        try {
            List<List<Object>> list = getCourseListByExcel(excelPath);
            List<ExcelData> excelDataList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                List<Object> objects = list.get(i);
                ExcelData excelData = new ExcelData();
                excelData.setName(objects.get(0).toString());
                excelData.setMobile(objects.get(1).toString());
                excelDataList.add(excelData);
            }
            for (ExcelData excelData : excelDataList) {
                System.out.println(excelData.getName() + excelData.getMobile());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            logger.info("结束");
        }
    }

    /**
     * 解压zip
     *
     * @param file 文件
     * @return
     */
    public static String unZip(File file) {
        long millis = System.currentTimeMillis();
        ZipFile zipFile = null;
        String dirPath = "";
        String parentSrc = file.getParentFile().getPath();
        try {
            zipFile = new ZipFile(file);
            Enumeration<?> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry element = (ZipEntry) entries.nextElement();
                // 过滤 __MACOSX 文件
                if (!element.getName().startsWith("__MACOSX")) {
                    if (element.isDirectory()) {
                        dirPath = parentSrc + "/" + element.getName();
                        File dir = new File(dirPath);
                        dir.mkdirs();
                    } else {
                        File targetFile = new File(parentSrc + "/" + element.getName());
                        if (!targetFile.getParentFile().exists()) {
                            targetFile.getParentFile().mkdirs();
                        }
                        targetFile.createNewFile();
                        InputStream is = zipFile.getInputStream(element);
                        FileOutputStream fos = new FileOutputStream(targetFile);
                        int len;
                        byte[] buff = new byte[1024];
                        while ((len = is.read(buff)) != -1) {
                            fos.write(buff, 0, len);
                        }
                        fos.close();
                        is.close();
                    }
                }
            }
            // 解压后删除源文件
            file.delete();
            long timeMillis = System.currentTimeMillis();
            logger.info("解压完成，耗时：{}", (timeMillis - millis) + " ms");
        } catch (Exception e) {
            throw new RuntimeException("unzip error from ZipUtils", e);
        } finally {
            try {
                if (zipFile != null) {
                    zipFile.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return dirPath;
    }

    /**
     * 压缩文件夹 zip
     *
     * @param file
     */
    public static void fileToZip(File file) {
        try {
            FileOutputStream fos = new FileOutputStream(file.getParent() + "/" + file.getName() + ".zip");
            ZipOutputStream zipOut = new ZipOutputStream(fos);
            toZip(file, file.getName(), zipOut);
            zipOut.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void toZip(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
        if (fileToZip.isDirectory()) {
            if (fileName.endsWith("/")) {
                zipOut.putNextEntry(new ZipEntry(fileName));
            } else {
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
            }
            zipOut.closeEntry();
            File[] children = fileToZip.listFiles();
            for (File childFile : children) {
                toZip(childFile, fileName + "/" + childFile.getName(), zipOut);
            }
            return;
        }
        FileChannel channel = new FileInputStream(fileToZip).getChannel();
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);
        while (true) {
            byteBuffer.clear();
            int read = channel.read(byteBuffer);
            if (read == -1) break;
            zipOut.write(byteBuffer.array());
        }
        channel.close();
    }


    /**
     * 阿里云oss对象存储
     */
    public static void fileToAliOss() {

    }

    /**
     * 腾讯oss对象存储
     * @param filePath 文件地址
     * @param parentPre 父级文件夹，名称
     */
    public static void fileToTXCos(String filePath, String parentPre) {
        File file = new File(filePath);
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                long preKey = new Date().getTime();
                String key = parentPre + "/" + file.getName() + "-" + preKey;
                TencentCos.cosUploadFile(f, key);
            }
        } else {
            long preKey = new Date().getTime();
            String fileName = parentPre + "/" + file.getName() + "-" + preKey;
            TencentCos.cosUploadFile(file, fileName);
        }
    }

    /**
     * 又拍云对象存储
     */
    public static void fileToUpyun() {

    }

    /**
     * 七牛云对象存储
     */
    public static void fileToQiniuyun() {

    }

    /**
     * 测试入口
     * @param args
     */
    public static void main(String[] args) {
        fileToZip(new File("src/main/resources/static/filePath"));
    }

}
